package com.ts.api.http.platform.biz;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.gitee.apanlh.util.algorithm.digest.MD5;
import com.gitee.apanlh.util.algorithm.encrypt.asymmetric.RSA;
import com.gitee.apanlh.util.algorithm.encrypt.symmetric.AES;
import com.gitee.apanlh.util.base.ChooseEq;
import com.gitee.apanlh.util.base.CollUtils;
import com.gitee.apanlh.util.base.Eq;
import com.gitee.apanlh.util.base.IteratorUtils;
import com.gitee.apanlh.util.cache.redis.RedisKeyBuilder;
import com.gitee.apanlh.util.cache.redis.api.RedisString;
import com.gitee.apanlh.util.dataformat.JsonUtils;
import com.gitee.apanlh.util.reflection.ClassConvertUtils;
import com.gitee.apanlh.util.valid.ValidParam;
import com.gitee.apanlh.web.model.vo.RequestVO;
import com.ts.api.common.util.H5DomainUrlUtils;
import com.ts.api.http.platform.entity.apply.ApiPlatApplyYueDaiBao;
import com.ts.api.http.platform.entity.dataexchange.ApiPlatDataExchangeYueDaiBao;
import com.ts.api.module.api.convert.core.annotation.ApiPlan;
import com.ts.api.module.api.convert.core.annotation.ApiPlanConvertType;
import com.ts.api.module.api.convert.core.entity.ApiApplyParameter;
import com.ts.api.module.api.convert.core.entity.ApiBizStatus;
import com.ts.api.module.api.convert.core.entity.ApiDataExchangeParameter;
import com.ts.api.module.api.convert.core.utils.ApiFieldConverter;
import com.ts.api.module.api.convert.platform.entity.RespPlatformMultiPhoneMaskDataExchange;
import com.ts.api.module.api.convert.platform.entity.RespPlatformNoticeApply;
import com.ts.api.module.api.convert.platform.entity.RespPlatformPhoneMaskApply;
import com.ts.api.module.api.convert.platform.entity.RespPlatformPhoneMaskDataExchange;
import com.ts.api.module.api.convert.platform.handler.ApiPlatformPhoneMaskConvertHandler;
import com.ts.api.module.api.entity.ApiProtocol;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.*;

/**
 * 安心分期&出悦贷宝全流程28MD5+掩码
 * https://yuedb.apifox.cn/  ydb123456
 * @author WJB
 */
@ApiPlan(productId = "326", type = ApiPlanConvertType.PLAT_PHONE_MASK)
public class ApiPlatYueDaiBaoPhoneMd5Convert implements ApiPlatformPhoneMaskConvertHandler {

    public static final String CHANNEL_ID = "d1039axfqAPI";
    public static final String PUBLIC_KEY_STR = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC7ad5Alwh5fdLyvCt3ruO3Js81Jek8m8DWlj5TE/CdTeX1CTv7WETg0cLZP9l//rGy1A667KgzQk0e0Uw4GkULy3NHPjsgO2SdCxiE9aQcGh9Eorf8s7u/rqwMRDiyZj1drQKcplsOScKPvePhqdiN+URsDHwPy6COktBRLoRsyQIDAQAB";
    private static final String PRIVATE_KEY_STR = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALCHLWefnA8M188LB7QUPUg5RgOhG+erPXp+SnMAu8vJeTYGGW/PekOv7Lveme9snxdwGONGELg7FNKbFVTe5HQueu/ywEVJo//xtxR166lc/HuhkUnAKlCjkVNEeHAH0yCDQrO7qK+fUJ5DUMpkCupDTGANWJyM9mRCQ5zB2W6tAgMBAAECgYAOr3Ariq+k4OCjLLu7U2O1um4Ep0Z3A1vd8NuorYrx7RTUVbWQA6acMupyxpXvwQ2LGZw4a//AE8orqxMfOFuw2zYBDueUXAXhvuMUEZPGWc5pzpk0kHnKiHQUWWJs2E0pRlqFqYpKL2EFzDAy/s7zO2oX1H9QOmNXhVbo0rSHAQJBAN3pIdk+MStToNKXipGEy6dV4pXTzUd7n1zHtRznrN4U4i2Gv1/TjnIaLVG69Uaz3otaOlapUVJ+uxovAVJNdD0CQQDLpVNo7SvNchinESAeQg54AnXgNktfBzPk/3wXGEOxQXTTZV5Jbacz0tc/0Bhmr8oO2EN0nKpfrRmhHGTkTtsxAkAGqQuiCJLTORRXncLD8Vdnc1V0p8G+hoBW+Yt/DZkLpVbQhP3Tc3cQB6caj+DyuU1Ro2ii1zwgnLsi4wxIGxkFAkEAhkV0kItIRUaEYKtW/Pxa49/jbrj9yyNJoSSe4e9auqXI7JU6rLmC9BWBXQ7M9+/SDyWinGGrqDfO3T6Ge05PEQJBAJcRVOGzLRJ1SQkj+Kt7j8yFOQIAOh8Ii5U2OyPPe1ypzWJlDESn/jw6LqvBMTD+m5Ec1Xn5Anxk3DtBQzLyOfI=";
    private static final String DEFAULT_ENCODING = "UTF-8";
    private static final String ALGORITHM_RSA = "RSA";
    public static final String ALGORITHM_SHA256 = "SHA256withRSA";
    public static final RedisString PLAN_MATCH_KEY = RedisKeyBuilder.builder().withKeys("temp_yue_dai_bao").buildString();

    @Override
    public Object dataExchange(ApiDataExchangeParameter apiDataExchangeParameter) {
        ApiPlatDataExchangeYueDaiBao data = new ApiPlatDataExchangeYueDaiBao();
        ApiFieldConverter apiFieldConverter = ApiFieldConverter.create(apiDataExchangeParameter);
        // 手机号掩码
        data.setPhoneMasking(apiDataExchangeParameter.getPhoneMask());
        // 掩码类型
        data.setMaskingType(8);
        // 姓名
        data.setNameMd5(MD5.create().digestToBase64Str("测试用户"));
        // 渠道
        data.setChannelCode(CHANNEL_ID);
        // 年龄
        data.setAge(apiFieldConverter.getAgeInt());
        //  性别 0-女 1-男 默认1
        String sex = apiDataExchangeParameter.getSex();
        Integer sexChoose = ChooseEq.create()
                .when(sex, "0", 1)
                .when(sex, "1", 0)
                .end(1);
        data.setSex(sexChoose);
        //  省份
        data.setProvinceName(apiDataExchangeParameter.getProvinceName());
        data.setProvinceCode(apiDataExchangeParameter.getProvinceCode());
        //  城市编码
        data.setCityCode(apiDataExchangeParameter.getAreaCode());
        //  城市
        data.setCityName(apiDataExchangeParameter.getCity());
        //  手机类型
        data.setSystem(1);
        data.setIp(apiDataExchangeParameter.getIp());
        //  贷款金额
        Integer money = ChooseEq.create()
                .when(apiDataExchangeParameter.getLoanAmount(), "1", 1)
                .when(apiDataExchangeParameter.getLoanAmount(), "2", 3)
                .when(apiDataExchangeParameter.getLoanAmount(), "3", 4)
                .when(apiDataExchangeParameter.getLoanAmount(), "4", 5)
                .end(1);
        data.setLoanAmount(money);
        //  可接受月供范围
        data.setRepaymentRange(1);
        //  贷款用途
        Integer loanUse = ChooseEq.create()
                .when(apiDataExchangeParameter.getLoanPurpose(), "1", 1)
                .when(apiDataExchangeParameter.getLoanPurpose(), "2", 2)
                .when(apiDataExchangeParameter.getLoanPurpose(), "3", 3)
                .when(apiDataExchangeParameter.getLoanPurpose(), "4", 4)
                .when(apiDataExchangeParameter.getLoanPurpose(), "5", 6)
                .when(apiDataExchangeParameter.getLoanPurpose(), "6", 5)
                .end(6);
        data.setLoanPurpose(loanUse);
        // 借款周期
        Integer time = ChooseEq.create()
                .when(apiDataExchangeParameter.getLoanTerm(), "1", 1)
                .when(apiDataExchangeParameter.getLoanTerm(), "2", 1)
                .when(apiDataExchangeParameter.getLoanTerm(), "3", 1)
                .when(apiDataExchangeParameter.getLoanTerm(), "4", 2)
                .when(apiDataExchangeParameter.getLoanTerm(), "5", 3)
                .when(apiDataExchangeParameter.getLoanTerm(), "6", 3)
                .end(1);
        data.setLoanCycle(time);
        //  学历
        Integer educationAttainment = ChooseEq.create()
                .when(apiDataExchangeParameter.getEducationAttainment(), "1", 1)
                .when(apiDataExchangeParameter.getEducationAttainment(), "2", 1)
                .when(apiDataExchangeParameter.getEducationAttainment(), "3", 1)
                .when(apiDataExchangeParameter.getEducationAttainment(), "4", 2)
                .when(apiDataExchangeParameter.getEducationAttainment(), "5", 3)
                .when(apiDataExchangeParameter.getEducationAttainment(), "6", 3)
                .end(1);
        data.setEducation(educationAttainment);
        //  职业
        Integer job = ChooseEq.create()
                .when(apiDataExchangeParameter.getCareer(), "1", 1)
                .when(apiDataExchangeParameter.getCareer(), "2", 4)
                .when(apiDataExchangeParameter.getCareer(), "3", 3)
                .when(apiDataExchangeParameter.getCareer(), "4", 5)
                .when(apiDataExchangeParameter.getCareer(), "5", 2)
                .end(1);
        data.setProfession(job);
        // 代发
        Integer salaryPayMethod = ChooseEq.create()
                .when(apiDataExchangeParameter.getSalaryPayMethod(), "1", 2)
                .when(apiDataExchangeParameter.getSalaryPayMethod(), "2", 1)
                .when(apiDataExchangeParameter.getSalaryPayMethod(), "3", 2)
                .end(1);
        data.setSalaryPaymentForm(salaryPayMethod);
        //  月收入
        Integer monthlySalary = ChooseEq.create()
                .when(apiDataExchangeParameter.getMonthlySalary(), "1", 1)
                .when(apiDataExchangeParameter.getMonthlySalary(), "2", 2)
                .when(apiDataExchangeParameter.getMonthlySalary(), "3", 3)
                .when(apiDataExchangeParameter.getMonthlySalary(), "4", 3)
                .when(apiDataExchangeParameter.getMonthlySalary(), "5", 3)
                .end(1);
        data.setMonthlyIncome(monthlySalary);
        //  房产情况
        Integer house = ChooseEq.create()
                .when(apiDataExchangeParameter.getRealEstateInfo(), "1", 1)
                .when(apiDataExchangeParameter.getRealEstateInfo(), "2", 2)
                .when(apiDataExchangeParameter.getRealEstateInfo(), "3", 2)
                .when(apiDataExchangeParameter.getRealEstateInfo(), "4", 2)
                .when(apiDataExchangeParameter.getRealEstateInfo(), "5", 2)
                .when(apiDataExchangeParameter.getRealEstateInfo(), "6", 2)
                .end(1);
        data.setHouse(house);
        //  车产
        Integer car = ChooseEq.create()
                .when(apiDataExchangeParameter.getCarInfo(), "1", 1)
                .when(apiDataExchangeParameter.getCarInfo(), "2", 2)
                .when(apiDataExchangeParameter.getCarInfo(), "3", 2)
                .when(apiDataExchangeParameter.getCarInfo(), "4", 2)
                .end(1);
        data.setCar(car);
        //  芝麻分
        Integer zhima = ChooseEq.create()
                .when(apiDataExchangeParameter.getSesameCredit(), "1", 1)
                .when(apiDataExchangeParameter.getSesameCredit(), "2", 1)
                .when(apiDataExchangeParameter.getSesameCredit(), "3", 2)
                .when(apiDataExchangeParameter.getSesameCredit(), "4", 3)
                .end(4);
        data.setAliFraction(zhima);
        // 信用卡
        Integer hasCredit = ChooseEq.create()
                .when(apiDataExchangeParameter.getCreditLimit(), "1", 1)
                .when(apiDataExchangeParameter.getCreditLimit(), "2", 2)
                .when(apiDataExchangeParameter.getCreditLimit(), "3", 3)
                .when(apiDataExchangeParameter.getCreditLimit(), "4", 5)
                .when(apiDataExchangeParameter.getCreditLimit(), "5", 5)
                .when(apiDataExchangeParameter.getCreditLimit(), "6", 2)
                .end(1);
        data.setCreditCardLimit(hasCredit);
        // 信用记录  1-无逾期 2-有逾期
        Integer creditHistory = ChooseEq.create()
                .when(apiDataExchangeParameter.getOverdue(), "1", 1)
                .when(apiDataExchangeParameter.getOverdue(), "2", 3)
                .when(apiDataExchangeParameter.getOverdue(), "3", 2)
                .end(2);
        data.setCreditReportOverdue(creditHistory);
        //  公积金
        Integer gongjijin = ChooseEq.create()
                .when(apiDataExchangeParameter.getProvidentFund(), "1", 3)
                .when(apiDataExchangeParameter.getProvidentFund(), "2", 1)
                .when(apiDataExchangeParameter.getProvidentFund(), "3", 2)
                .when(apiDataExchangeParameter.getProvidentFund(), "4", 1)
                .end(3);
        data.setProvidentFund(gongjijin);
        //  社保
        Integer shebao = ChooseEq.create()
                .when(apiDataExchangeParameter.getSocialSecurity(), "1", 3)
                .when(apiDataExchangeParameter.getSocialSecurity(), "2", 1)
                .when(apiDataExchangeParameter.getSocialSecurity(), "3", 2)
                .when(apiDataExchangeParameter.getSocialSecurity(), "4", 1)
                .end(3);
        data.setSocialSecurity(shebao);
        //  保单
        Integer baodanIs = ChooseEq.create()
                .when(apiDataExchangeParameter.getInsurancePolicy(), "1", 1)
                .when(apiDataExchangeParameter.getInsurancePolicy(), "2", 2)
                .when(apiDataExchangeParameter.getInsurancePolicy(), "3", 3)
                .when(apiDataExchangeParameter.getInsurancePolicy(), "4", 2)
                .end(1);
        data.setInsurancePolicy(baodanIs);
        // AES密钥
        String encodedKey = generate16CharBase64Key();
        AES aes = AES.createEcb(encodedKey.getBytes());
        String dataStr = aes.encryptToBase64Str(JsonUtils.toJson(data));

        RSA rsa = new RSA(PUBLIC_KEY_STR, null);
        String KEY = rsa.encryptToBase64Str(encodedKey);
        TreeMap<String, Object> newMap = new TreeMap<>();
        newMap.put("serialNo", apiDataExchangeParameter.getReqId());
        newMap.put("timestamp", ClassConvertUtils.toStr(System.currentTimeMillis()));
        newMap.put("merchantId", CHANNEL_ID);
        newMap.put("secretKey", KEY);
        newMap.put("body", dataStr);
        ApiPlatYueDaiBaoPhoneMd5Convert.PLAN_MATCH_KEY.setForMinutes(apiDataExchangeParameter.getReqId(), encodedKey, 10L);

        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, Object> entry : newMap.entrySet()) {
            if (entry.getValue() != null) {
                sb.append(entry.getValue());
            }
        }
        String signature = signWithPriKey(sb.toString(), PRIVATE_KEY_STR);

        newMap.put("signature", signature);
        return JsonUtils.toJson(newMap);
    }

    @Override
    public Object apply(ApiApplyParameter apiApplyParameter) {
        ApiPlatApplyYueDaiBao data = new ApiPlatApplyYueDaiBao();
        ApiFieldConverter apiFieldConverter = ApiFieldConverter.create(apiApplyParameter);
        // 手机号
        data.setPhone(apiApplyParameter.getPhone());
        // 姓名
        data.setRealName(apiApplyParameter.getUserName());
        // 渠道
        data.setChannelCode(CHANNEL_ID);
        // 协议
        ApiPlatApplyYueDaiBao.AgreementList agreementList = new ApiPlatApplyYueDaiBao.AgreementList();
        agreementList.setAgreementName("用户授权协议");
        agreementList.setAgreementUrl(H5DomainUrlUtils.createUserProtocolUrl(apiApplyParameter.getProductPlanId(), apiApplyParameter.getPhoneMd5()));
        List<ApiPlatApplyYueDaiBao.AgreementList> agreementLists = new ArrayList<>();
        agreementLists.add(agreementList);
        data.setAgreementList(agreementLists);
        // 年龄
        data.setAge(apiFieldConverter.getAgeInt());
        //  性别 0-女 1-男 默认1
        String sex = apiApplyParameter.getSex();
        Integer sexChoose = ChooseEq.create()
                .when(sex, "0", 1)
                .when(sex, "1", 0)
                .end(1);
        data.setSex(sexChoose);
        //  省份
        data.setProvinceName(apiApplyParameter.getProvinceName());
        data.setProvinceCode(apiApplyParameter.getProvinceCode());
        //  城市编码
        data.setCityCode(apiApplyParameter.getAreaCode());
        //  城市
        data.setCityName(apiApplyParameter.getCity());
        //  手机类型
        data.setSystem(1);
        data.setIp(apiApplyParameter.getIp());
        //  贷款金额
        Integer money = ChooseEq.create()
                .when(apiApplyParameter.getLoanAmount(), "1", 1)
                .when(apiApplyParameter.getLoanAmount(), "2", 3)
                .when(apiApplyParameter.getLoanAmount(), "3", 4)
                .when(apiApplyParameter.getLoanAmount(), "4", 5)
                .end(1);
        data.setLoanAmount(money);
        //  可接受月供范围
        data.setRepaymentRange(1);
        //  贷款用途
        Integer loanUse = ChooseEq.create()
                .when(apiApplyParameter.getLoanPurpose(), "1", 1)
                .when(apiApplyParameter.getLoanPurpose(), "2", 2)
                .when(apiApplyParameter.getLoanPurpose(), "3", 3)
                .when(apiApplyParameter.getLoanPurpose(), "4", 4)
                .when(apiApplyParameter.getLoanPurpose(), "5", 6)
                .when(apiApplyParameter.getLoanPurpose(), "6", 5)
                .end(6);
        data.setLoanPurpose(loanUse);
        // 借款周期
        Integer time = ChooseEq.create()
                .when(apiApplyParameter.getLoanTerm(), "1", 1)
                .when(apiApplyParameter.getLoanTerm(), "2", 1)
                .when(apiApplyParameter.getLoanTerm(), "3", 1)
                .when(apiApplyParameter.getLoanTerm(), "4", 2)
                .when(apiApplyParameter.getLoanTerm(), "5", 3)
                .when(apiApplyParameter.getLoanTerm(), "6", 3)
                .end(1);
        data.setLoanCycle(time);
        //  学历
        Integer educationAttainment = ChooseEq.create()
                .when(apiApplyParameter.getEducationAttainment(), "1", 1)
                .when(apiApplyParameter.getEducationAttainment(), "2", 1)
                .when(apiApplyParameter.getEducationAttainment(), "3", 1)
                .when(apiApplyParameter.getEducationAttainment(), "4", 2)
                .when(apiApplyParameter.getEducationAttainment(), "5", 3)
                .when(apiApplyParameter.getEducationAttainment(), "6", 3)
                .end(1);
        data.setEducation(educationAttainment);
        //  职业
        Integer job = ChooseEq.create()
                .when(apiApplyParameter.getCareer(), "1", 1)
                .when(apiApplyParameter.getCareer(), "2", 4)
                .when(apiApplyParameter.getCareer(), "3", 3)
                .when(apiApplyParameter.getCareer(), "4", 5)
                .when(apiApplyParameter.getCareer(), "5", 2)
                .end(1);
        data.setProfession(job);
        // 代发
        Integer salaryPayMethod = ChooseEq.create()
                .when(apiApplyParameter.getSalaryPayMethod(), "1", 2)
                .when(apiApplyParameter.getSalaryPayMethod(), "2", 1)
                .when(apiApplyParameter.getSalaryPayMethod(), "3", 2)
                .end(1);
        data.setSalaryPaymentForm(salaryPayMethod);
        //  月收入
        Integer monthlySalary = ChooseEq.create()
                .when(apiApplyParameter.getMonthlySalary(), "1", 1)
                .when(apiApplyParameter.getMonthlySalary(), "2", 2)
                .when(apiApplyParameter.getMonthlySalary(), "3", 3)
                .when(apiApplyParameter.getMonthlySalary(), "4", 3)
                .when(apiApplyParameter.getMonthlySalary(), "5", 3)
                .end(1);
        data.setMonthlyIncome(monthlySalary);
        //  房产情况
        Integer house = ChooseEq.create()
                .when(apiApplyParameter.getRealEstateInfo(), "1", 1)
                .when(apiApplyParameter.getRealEstateInfo(), "2", 2)
                .when(apiApplyParameter.getRealEstateInfo(), "3", 2)
                .when(apiApplyParameter.getRealEstateInfo(), "4", 2)
                .when(apiApplyParameter.getRealEstateInfo(), "5", 2)
                .when(apiApplyParameter.getRealEstateInfo(), "6", 2)
                .end(1);
        data.setHouse(house);
        //  车产
        Integer car = ChooseEq.create()
                .when(apiApplyParameter.getCarInfo(), "1", 1)
                .when(apiApplyParameter.getCarInfo(), "2", 2)
                .when(apiApplyParameter.getCarInfo(), "3", 2)
                .when(apiApplyParameter.getCarInfo(), "4", 2)
                .end(1);
        data.setCar(car);
        //  芝麻分
        Integer zhima = ChooseEq.create()
                .when(apiApplyParameter.getSesameCredit(), "1", 1)
                .when(apiApplyParameter.getSesameCredit(), "2", 1)
                .when(apiApplyParameter.getSesameCredit(), "3", 2)
                .when(apiApplyParameter.getSesameCredit(), "4", 3)
                .end(4);
        data.setAliFraction(zhima);
        // 信用卡
        Integer hasCredit = ChooseEq.create()
                .when(apiApplyParameter.getCreditLimit(), "1", 1)
                .when(apiApplyParameter.getCreditLimit(), "2", 2)
                .when(apiApplyParameter.getCreditLimit(), "3", 3)
                .when(apiApplyParameter.getCreditLimit(), "4", 5)
                .when(apiApplyParameter.getCreditLimit(), "5", 5)
                .when(apiApplyParameter.getCreditLimit(), "6", 2)
                .end(1);
        data.setCreditCardLimit(hasCredit);
        // 信用记录  1-无逾期 2-有逾期
        Integer creditHistory = ChooseEq.create()
                .when(apiApplyParameter.getOverdue(), "1", 1)
                .when(apiApplyParameter.getOverdue(), "2", 3)
                .when(apiApplyParameter.getOverdue(), "3", 2)
                .end(2);
        data.setCreditReportOverdue(creditHistory);
        //  公积金
        Integer gongjijin = ChooseEq.create()
                .when(apiApplyParameter.getProvidentFund(), "1", 3)
                .when(apiApplyParameter.getProvidentFund(), "2", 1)
                .when(apiApplyParameter.getProvidentFund(), "3", 2)
                .when(apiApplyParameter.getProvidentFund(), "4", 1)
                .end(3);
        data.setProvidentFund(gongjijin);
        //  社保
        Integer shebao = ChooseEq.create()
                .when(apiApplyParameter.getSocialSecurity(), "1", 3)
                .when(apiApplyParameter.getSocialSecurity(), "2", 1)
                .when(apiApplyParameter.getSocialSecurity(), "3", 2)
                .when(apiApplyParameter.getSocialSecurity(), "4", 1)
                .end(3);
        data.setSocialSecurity(shebao);
        //  保单
        Integer baodanIs = ChooseEq.create()
                .when(apiApplyParameter.getInsurancePolicy(), "1", 1)
                .when(apiApplyParameter.getInsurancePolicy(), "2", 2)
                .when(apiApplyParameter.getInsurancePolicy(), "3", 3)
                .when(apiApplyParameter.getInsurancePolicy(), "4", 2)
                .end(1);
        data.setInsurancePolicy(baodanIs);
        String key = ApiPlatYueDaiBaoPhoneMd5Convert.PLAN_MATCH_KEY.get(apiApplyParameter.getReqId(), String.class);

        // 加密
        AES aes = AES.createEcb(key.getBytes());
        String dataStr = aes.encryptToBase64Str(JsonUtils.toJson(data));
        RSA rsa = new RSA(PUBLIC_KEY_STR, null);
        String KEY = rsa.encryptToBase64Str(key);
        TreeMap<String, Object> newMap = new TreeMap<>();
        newMap.put("serialNo", apiApplyParameter.getReqId());
        newMap.put("timestamp", ClassConvertUtils.toStr(System.currentTimeMillis()));
        newMap.put("merchantId", CHANNEL_ID);
        newMap.put("secretKey", KEY);
        newMap.put("body", dataStr);

        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, Object> entry : newMap.entrySet()) {
            if (entry.getValue() != null) {
                sb.append(entry.getValue());
            }
        }

        String signature = signWithPriKey(sb.toString(), PRIVATE_KEY_STR);

        newMap.put("signature", signature);
        return JsonUtils.toJson(newMap);
    }

    @Override
    public RespPlatformPhoneMaskApply respApply(String respJson) {
        JSONObject jsonObject = JsonUtils.get(respJson);
        if (jsonObject == null) {
            return RespPlatformPhoneMaskApply.ofFail();
        }
        String body = jsonObject.getString("body");
        String secretKey = jsonObject.getString("secretKey");

        RSA rsa = new RSA(null, PRIVATE_KEY_STR);
        String aesKey = rsa.decryptFromBase64Str(secretKey);

        AES aes = AES.createEcb(aesKey.getBytes());
        String bodyData = aes.decryptFromBase64Str(body.getBytes());
        JSONObject bodyObject = JsonUtils.get(bodyData);

        JSONObject resData = bodyObject.getJSONObject("body");
        Integer applyStatus = resData.getInteger("applyStatus");
        if (!Eq.object(applyStatus, 200)) {
            return RespPlatformPhoneMaskApply.ofFail();
        }

        if (!Eq.object(jsonObject.getInteger("errCode"), 0)) {
            return RespPlatformPhoneMaskApply.ofFail();
        }
        return RespPlatformPhoneMaskApply.ofSuc();
    }

    @Override
    public RespPlatformNoticeApply parseApplyNotice(RequestVO requestVO) {
        return null;
    }

    @Override
    public Map<String, Object> respApplyNotice(ApiBizStatus apiBizStatus) {
        return Map.of();
    }

    @Override
    public RespPlatformMultiPhoneMaskDataExchange respDataExchange(String respJson) {
        JSONObject jsonObject = JsonUtils.get(respJson);
        if (jsonObject == null) {
            return RespPlatformMultiPhoneMaskDataExchange.ofFail();
        }
        if (!Eq.object(jsonObject.getInteger("errCode"), 0)) {
            return RespPlatformMultiPhoneMaskDataExchange.ofFail();
        }

        String body = jsonObject.getString("body");
        if (ValidParam.isEmpty(body)) {
            return RespPlatformMultiPhoneMaskDataExchange.ofFail();
        }

        String secretKey = jsonObject.getString("secretKey");
        if (ValidParam.isEmpty(secretKey)) {
            return RespPlatformMultiPhoneMaskDataExchange.ofFail();
        }

        RSA rsa = new RSA(null, PRIVATE_KEY_STR);
        String aesKey = rsa.decryptFromBase64Str(secretKey);

        AES aes = AES.createEcb(aesKey.getBytes());
        String bodyData = aes.decryptFromBase64Str(body.getBytes());
        JSONObject bodyObject = JsonUtils.get(bodyData);

        JSONObject resData = bodyObject.getJSONObject("body");
        Integer accessStatus = resData.getInteger("accessStatus");
        if (!Eq.object(accessStatus, 2)) {
            return RespPlatformMultiPhoneMaskDataExchange.ofFail();
        }

        RespPlatformMultiPhoneMaskDataExchange respPlatformMultiPhoneMaskDataExchange = RespPlatformMultiPhoneMaskDataExchange.ofSuc();
        List<RespPlatformPhoneMaskDataExchange> listRespPlatformPhoneMaskDataExchange = CollUtils.newArrayList();
        JSONObject productInfo = resData.getJSONObject("productInfo");
        BigDecimal price = productInfo.getBigDecimal("productPrice");
        BigDecimal dividedPrice = price.divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
        String companyName = productInfo.getString("productOrgName");
        String productName = productInfo.getString("productName");
        String logo = productInfo.getString("logoUrl");

        List<ApiProtocol> protocolList = new ArrayList<>();
        //  获取协议
        JSONArray agreementList = resData.getJSONArray("agreementList");
        IteratorUtils.array(agreementList, (protocolResult, index) -> {
            JSONObject protocolObject = agreementList.getJSONObject(index);
            ApiProtocol protocol = new ApiProtocol();
            protocol.setProtocolName(protocolObject.getString("agreementName"));
            protocol.setProtocolUrl(protocolObject.getString("agreementUrl"));
            protocolList.add(protocol);
        });

        List<String> phoneMd5List = new ArrayList<>();
        JSONArray jsonArray = resData.getJSONArray("phoneMd5List");
        IteratorUtils.array(jsonArray, (md5List, index) -> {
            String phoneMd5 = jsonArray.getString(index);
            phoneMd5List.add(phoneMd5);
        });

        RespPlatformPhoneMaskDataExchange result = RespPlatformPhoneMaskDataExchange.of();
        result.setPrice(dividedPrice);
        result.setLogoPath(logo);
        result.setDisplayName(companyName);
        result.setProductName(productName);
        result.setProtocolList(protocolList);
        result.setListPhoneMd5(phoneMd5List);

        listRespPlatformPhoneMaskDataExchange.add(result);
        respPlatformMultiPhoneMaskDataExchange.setListPhoneMask(listRespPlatformPhoneMaskDataExchange);
        return respPlatformMultiPhoneMaskDataExchange;
    }

    public static String generate16CharBase64Key() {
        // 12字节原始数据 = 16字符Base64编码
        byte[] keyBytes = new byte[12];
        new SecureRandom().nextBytes(keyBytes);
        return Base64.getEncoder().encodeToString(keyBytes);
    }

    public static String signWithPriKey(String plainText, String privateKeyStr) {
        return signWithPriKey(plainText, privateKeyStr, ALGORITHM_SHA256);
    }

    private static RSAPrivateKey loadRsaPrivateKey(String priKeyText) throws NoSuchAlgorithmException, InvalidKeySpecException {
        byte[] keyBytes = Base64.getDecoder().decode(priKeyText);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_RSA);
        return (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
    }

    /**
     * @param plainText
     * @param privateKeyStr
     * @param algorithm
     * @return
     */
    public static String signWithPriKey(String plainText, String privateKeyStr, String algorithm) {
        try {
            Signature privateSignature = Signature.getInstance(algorithm);
            privateSignature.initSign(loadRsaPrivateKey(privateKeyStr));
            privateSignature.update(plainText.getBytes(DEFAULT_ENCODING));
            byte[] signature = privateSignature.sign();
            return Base64.getEncoder().encodeToString(signature);
        } catch (Exception e) {
            throw new RuntimeException("signWithPriKey error", e);
        }
    }

}
